home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-02-26 | 9.0 KB | 337 lines | [TEXT/CWIE] |
- /***
- File: LRequest.cp
-
-
- Contains: A Single Request thread class
-
-
- Written by: Ken Wieschhoff
-
-
- Copyright: ©1996 Siren Enterprises, All Rights Reserved.
-
-
- Change History (most recent first):
-
-
-
- <1> 9/5/96 kw Original
-
- ***/
-
-
- #include "LMainCGI.h"
- #include "LRequest.h"
- #include <string.h>
- #include <UMemoryMgr.h>
-
- extern AEIdleUPP LMainCGI::sIdleUPP;
- extern long LCGIStatusThread::sTotalConnections;
- extern Boolean LCGIStatusThread::sNeedsUpdate;
-
- #define kMaxRows 20
- #define kBufferSize 2048
- #define kAEClassCGI 'WWWΩ'
- #define kAESendPartial 'SPar'
- #define kCGIPartialData '----'
- #define kMoreData true
- #define kSendNow true
-
-
- // ---------------------------------------------------------------------------
- // • Constructor
- // ---------------------------------------------------------------------------
- LRequest::LRequest(AEAddressDesc WebStar, long connectionID, Handle formData)
- : LThread( false )
- {
- // Save the WebStar return address
- mWebSTAR = WebStar;
-
- // Same with the connection ID
- mConnectionID = connectionID;
-
- // Make a new handle stream to buffer replies.
- mData = new LHandleStream;
-
- // Make a local copy of the form data so the sender may delete
- // their copy.
- mFormData = formData;
- HandToHand( &mFormData);
-
- // Increment the total amount of connections received.
- LCGIStatusThread::sTotalConnections++;
-
- // Indicate to the main thread the window needs updating.
- LCGIStatusThread::sNeedsUpdate = true;
- }
-
- // ---------------------------------------------------------------------------
- // • Destructor
- // ---------------------------------------------------------------------------
- LRequest::~LRequest()
- {
- // dispose of the WebSTAR descriptor
- AEDisposeDesc ( &mWebSTAR );
-
- // Delete the Handle Stream
- delete mData;
-
- // Chuck the form data
- ::DisposeHandle( mFormData);
-
- // Indicate to the main thread the window needs updating.
- LCGIStatusThread::sNeedsUpdate = true;
- }
-
-
- // ---------------------------------------------------------------------------
- // • Run
- // ---------------------------------------------------------------------------
- void*
- LRequest::Run()
- {
-
- LStr255 HTTPHeader("\"HTTP/1.0\" 200\r\n\r\n");
- LStr255 HTMLPageTitle( "<HEAD><TITLE>Send Partial Test Page</TITLE></HEAD>");
- LStr255 HTMLPageStart( "<H2>SendPartial Results</H2>");
- LStr255 HTMLTableStart( "<P><TABLE BORDER>");
- LStr255 HTMLRowStart( "<TR>");
- LStr255 HTMLRowEnd( "</TR>");
- LStr255 HTMLTableCell( "<TD align=left><P>??Item??</TD>");
- LStr255 HTMLTableEnd( "</TABLE></TD></TR></TABLE></P>");
-
- long numberOfRows = 5, numberOfColumns = 6;
- long index, jndex;
- LStr255 itsCell, itemTemplate("??Item??");
- LStr255 cellData;
- Uint8 start;
-
- // Yield to the main thread to let the AppleEvent complete and send the "<SEND_PARTIAL>"
- // string to WebSTAR.
- LThread::Yield();
-
- Try_ {
-
- // Send the header
- ThrowIfOSErr_( SendData( &HTTPHeader[1], HTTPHeader.Length(), kMoreData, kSendNow));
-
- // Send the page title
- ThrowIfOSErr_( SendData( &HTMLPageTitle[1], HTMLPageTitle.Length(), kMoreData, !kSendNow));
-
- // Send the page start
- ThrowIfOSErr_( SendData( &HTMLPageStart[1], HTMLPageStart.Length(), kMoreData, !kSendNow));
-
- // Send the table start
- ThrowIfOSErr_( SendData( &HTMLTableStart[1], HTMLTableStart.Length(), kMoreData, !kSendNow));
- LThread::Yield();
-
- ParseData( &numberOfRows, &numberOfColumns);
-
- for ( index = 0; index <= numberOfRows; index++) {
-
- // Send the row start
- ThrowIfOSErr_( SendData( &HTMLRowStart[1], HTMLRowStart.Length(), kMoreData, !kSendNow));
-
- for ( jndex = 0; jndex <= numberOfColumns; jndex++) {
- // populate each cell like a spreadsheet
- FormatCell( index, jndex, cellData);
-
- // Initialize the cell to the template
- itsCell = HTMLTableCell;
-
- // Replace the template with the returned cell data.
- start = itsCell.Find(&itemTemplate[1],itemTemplate.Length(),0);
- itsCell.Remove(start, itemTemplate.Length());
- itsCell.Insert(&cellData[1], cellData[0], start);
-
- // Send the cell
- ThrowIfOSErr_( SendData( &itsCell[1], itsCell.Length(), kMoreData, !kSendNow));
- }
- // Send the row end
- ThrowIfOSErr_( SendData( &HTMLRowEnd[1], HTMLRowEnd.Length(), kMoreData, !kSendNow));
- LThread::Yield();
- }
- // Send the table end
- ThrowIfOSErr_( SendData( &HTMLTableEnd[1], HTMLTableEnd.Length(), !kMoreData, kSendNow));
-
- } Catch_ (inErr) {
- // Ignore any errors.
- } EndCatch_;
-
- // Make the window redraw
- LCGIStatusThread::sNeedsUpdate = true;
-
- DeleteThread();
- return nil;
- }
-
- // ---------------------------------------------------------------------------
- // • SendData
- // ---------------------------------------------------------------------------
- OSErr
- LRequest::SendData( unsigned char *data, Size itsLength, Boolean more, Boolean sendNow) {
-
- OSErr itsErr = noErr;
- long byteCount = itsLength;
- long amountSent = 0;
-
- // If this will fill the buffer, send it and "empty" the buffer.
- if (( GetHandleSize(mData->GetDataHandle()) + itsLength) > kBufferSize)
- itsErr = ReturnDataToClient( more);
-
- if ( itsErr == noErr) {
- // Put the data into the stream
- mData->PutBytes( data, byteCount);
-
- // Make sure it all went. If not, send what fit in the buffer and
- // repack the buffer.
- amountSent = byteCount;
- while ((itsErr == noErr) && ( amountSent < itsLength) ) {
- itsErr = ReturnDataToClient( true);
-
- byteCount = itsLength - amountSent;
- mData->PutBytes( &data[amountSent+1], byteCount);
- amountSent += byteCount;
- }
-
- // No more data or "send immediately". Flush the buffer.
- if (( itsErr == noErr) && (!more || sendNow))
- itsErr = ReturnDataToClient( more);
-
- }
-
- return ( itsErr);
- }
-
- // ---------------------------------------------------------------------------
- // • ReturnDataToClient
- // ---------------------------------------------------------------------------
- OSErr
- LRequest::ReturnDataToClient( Boolean more) {
-
- AEAddressDesc theAddress;
- AppleEvent ourEvent, ourReply;
- OSErr itsErr = noErr;
- short AEerr = noErr;
- long actualSize;
- DescType returnedType;
- Handle itsData = mData->GetDataHandle();
- StHandleLocker itsLocked( itsData);
-
- Try_ {
- // Duplicate the address
- ThrowIfOSErr_( AEDuplicateDesc( &mWebSTAR, &theAddress));
-
- // Create the Event
- ThrowIfOSErr_( AECreateAppleEvent(kAEClassCGI,kAESendPartial, &theAddress,
- kAutoGenerateReturnID, kAnyTransactionID, &ourEvent));
-
- // Add our data
- ThrowIfOSErr_( AEPutParamPtr( &ourEvent, kCGIPartialData, typeChar,
- *itsData, GetHandleSize( itsData)));
-
- // Add the connection ID
- ThrowIfOSErr_( AEPutParamPtr( &ourEvent, 'Kcid', typeLongInteger,
- &mConnectionID, sizeof(mConnectionID)));
-
- // Add the "more data" flag.
- ThrowIfOSErr_( AEPutParamPtr( &ourEvent, 'Kmor', typeBoolean, &more,
- sizeof(more)));
-
- // Send the event. If the client has gone away this should return an error
- itsErr = AESend( &ourEvent, &ourReply, kAEWaitReply + kAENeverInteract,
- kAENormalPriority, kAEDefaultTimeout, nil, nil);
-
-
- // extract the error reply */
- if ( itsErr == noErr) {
- AEerr = noErr;
- itsErr = AEGetParamPtr ( &ourReply, keyErrorNumber, typeSMInt, &returnedType, &AEerr,
- sizeof(AEerr), &actualSize );
-
- if (itsErr == errAEDescNotFound)
- itsErr = noErr;
- }
-
-
- } Catch_ (inErr) {
- // Ignore any errors.
- } EndCatch_;
-
- // Reset the buffer to 0.
- mData->SetLength( 0);
- mData->SetMarker( 0, streamFrom_Start);
-
- AEDisposeDesc ( &theAddress );
- AEDisposeDesc ( &ourEvent );
- AEDisposeDesc ( &ourReply );
-
- if ( AEerr != noErr)
- itsErr = AEerr;
-
- return itsErr;
-
- }
-
- // ---------------------------------------------------------------------------
- // • FormatCell
- // ---------------------------------------------------------------------------
- void
- LRequest::FormatCell( long row, long column, LStr255 &cellData) {
-
- Uchar columnCharacter;
-
- // Set the cell descriptor empty
- cellData = "\p";
-
- // Add the row number
- if ( row > 0)
- cellData = cellData + (LStr255)row;
-
- // Add the column as a character
- if ( column > 0) {
- columnCharacter = 'A' + column - 1;
- cellData = cellData + (LStr255)columnCharacter;
- }
-
- }
-
- // ---------------------------------------------------------------------------
- // • ParseData
- // ---------------------------------------------------------------------------
- void
- LRequest::ParseData( long *row, long *column) {
-
- LStr255 itsData(mFormData), itsValue;
- UInt8 start, end;
- char *rowsTag = "Rows=";
- char *columnsTag = "Columns=";
- char itsColumn;
-
- // Find the start of rows tag
- start = itsData.Find(rowsTag,strlen(rowsTag),0);
-
- // If found...
- if ( start) {
- start += strlen(rowsTag);
- // Grab the substring from after the tag to the '&' delimiter
- end = itsData.Find("&",1,start);
- itsValue = itsData(start,end - start);
- // Convert to a long
- *row = itsValue;
- }
-
- // Find the columns tag. This is capital letter.
- start = itsData.Find(columnsTag, strlen(columnsTag), 0);
-
- if ( start) {
- start += strlen(columnsTag);
- end = itsData.Find("&",1,start);
- // Grab the substring from after the tag to the '&' delimiter
- itsValue = itsData(start,end - start);
- // Convert to a decimal value.
- itsColumn = itsValue[1];
- *column = itsColumn - 'A' + 1;
- }
- }
-